//!互斥量和读写锁
//Mutex 意为互斥对象，用来保护共享数据。Mutex 有下面几个特征：
//Mutex 会等待获取锁令牌(token)，在等待过程中，会阻塞线程。直到锁令牌得到。同时只有一个线程的 Mutex 对象获取到锁；
// Mutex 通过 .lock() 或 .try_lock() 来尝试得到锁令牌，被保护的对象，必须通过这两个方法返回的 RAII 守卫来调用，不能直接操作；
// 当 RAII 守卫作用域结束后，锁会自动解开；
// 在多线程中，Mutex 一般和 Arc 配合使用。


use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc;
use std::sync::RwLock;

const N: i32 = 10;

#[test]
pub fn mutex_demo(){

// Spawn a few threads to increment a shared variable (non-atomically), and
// let the main thread know once all increments are done.
//
// Here we're using an Arc to share memory among threads, and the data inside
// the Arc is protected with a mutex.
    //互斥量 使用Arc引用计数
    let data: Arc<Mutex<i32>> = Arc::new(Mutex::new(0));

    //通道
    let (tx, rx): (mpsc::Sender<()>, mpsc::Receiver<()>) = channel();
    for _ in 0..10 {
        //元组，互斥量， 通道发送者
        let (data, tx) = (data.clone(), tx.clone());
        thread::spawn(move || {
// The shared state can only be accessed once the lock is held.
// Our non-atomic increment is safe because we're the only thread
// which can access the shared state when the lock is held.
//
// We unwrap() the return value to assert that we are not expecting
// threads to ever fail while holding the lock.
            //加锁
            let mut data = data.lock().unwrap();
            *data += 1; //改变数据
            if *data == N {
                tx.send(()).unwrap();
            }
// the lock is unlocked here when `data` goes out of scope.
        });
    }

    rx.recv().unwrap();
    println!("{}", data.lock().unwrap());//10
}

//lock 与 try_lock 的区别
// .lock() 方法，会等待锁令牌，等待的时候，会阻塞当前线程。而 .try_lock() 方法，只是做一次尝试操作，不会阻塞当前线程。
//
// 当 .try_lock() 没有获取到锁令牌时，会返回 Err。因此，如果要使用 .try_lock()，需要对返回值做仔细处理（比如，在一个循环检查中）。


//RwLock
// RwLock 翻译成 读写锁。它的特点是：
//
// 同时允许多个读，最多只能有一个写；
// 读和写不能同时存在；
// 比如：

#[test]
pub fn rw_lock_demo(){
    let lock = RwLock::new(5);
    // many reader locks can be held at once 同一时刻可以加多个读锁
    {
        let r1 = lock.read().unwrap();
        let r2 = lock.read().unwrap();
        assert_eq!(*r1, 5);
        assert_eq!(*r2, 5);
    } // read locks are dropped at this point 离开作用域，读锁释放

// only one write lock may be held, however 同一时刻只能加一个写锁
    {
        let mut w = lock.write().unwrap();
        *w += 1;
        assert_eq!(*w, 6);
    } // write lock is dropped here 离开作用域，写锁释放

}
//读写锁的方法
// .read()
// .try_read()
// .write()
// .try_write()
// 注意需要对 .try_read() 和 .try_write() 的返回值进行判断。
